﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Threading;
using System.Collections.Generic;
using System.Linq;

namespace TetrisClient
{
    /// <summary>
    /// This class represents the thread that controls the grid showing the
    /// next tetromino that will appear on the game board.
    /// </summary>
    public class NextTetrominoThread
    {
        private static readonly int INVALID_NEXT_TETROMINO = -1;

        private int[][] board = null;
        private volatile bool shutdown = false;

        private Grid nextTetrominoGrid;
        private Thread thread;
        private GridManipulator gridManipulator;
        private int nextTetromino = INVALID_NEXT_TETROMINO;

        /// <summary>
        /// Initializes a new instance of the <see cref="NextTetrominoThread"/> class.
        /// </summary>
        /// <param name="nextTetrominoGrid">The next tetromino grid.</param>
        public NextTetrominoThread(Grid nextTetrominoGrid)
        {
            this.nextTetrominoGrid = nextTetrominoGrid;
            gridManipulator = new GridManipulator(nextTetrominoGrid);
            thread = new Thread(run);
        }

        /// <summary>
        /// Creates the next tetromino board.
        /// </summary>
        /// <param name="numColumns">The num columns.</param>
        /// <param name="numRow">The num row.</param>
        public void createNextTetrominoBoard(int numColumns, int numRow)
        {
            gridManipulator.createGameBoard(numColumns, numRow);
        }

        /// <summary>
        /// Sets the next tetromino to be showed on the grid.
        /// </summary>
        /// <param name="next">The next.</param>
        /// <returns></returns>
        public bool setNextTetromino(int next)
        {
            if (nextTetromino != next)
            {
                nextTetromino = next;
                return true;
            }
            return false;
        }

        /// <summary>
        /// Updates the next tetromino.
        /// </summary>
        /// <param name="board">The board.</param>
        public void updateNextTetromino(int[][] board)
        {
            Monitor.Enter(this);
            try
            {
                this.board = board;
                Monitor.Pulse(this);
            }
            finally
            {
                Monitor.Exit(this);
            }
        }

        /// <summary>
        /// Runs this instance.
        /// </summary>
        private void run()
        {
            while (!shutdown)
            {
                Monitor.Enter(this);
                try
                {
                    Monitor.Wait(this);
                    ThreadActionExecutor.execute(() => updateTetromino());
                }
                finally
                {
                    Monitor.Exit(this);
                }
            }
        }

        /// <summary>
        /// Starts the thread.
        /// </summary>
        public void startThread()
        {
            thread.Start();
        }

        /// <summary>
        /// Stops the thread.
        /// </summary>
        public void stopThread()
        {
            shutdown = true;
        }

        /// <summary>
        /// Updates the tetromino.
        /// </summary>
        private void updateTetromino()
        {
            gridManipulator.updateGameBoard(board);
        }
    }
}
